import { _decorator, AudioClip, AudioSource, CCFloat, CCInteger, CircleCollider2D, Collider2D, Component, Contact2DType, director, instantiate, Label, Node, Prefab, RichText, UITransform, Vec2, Vec3 } from 'cc';
import { Joystick } from './Joystick';
const { ccclass, property } = _decorator;

@ccclass('Head')
export class Head extends Component {
    
    //蛇身预制体
    @property(Prefab)
    public bodyPrefab: Prefab = null;

    //食物
    @property(Prefab)
    public foodPrefab: Prefab = null;

    //蛇身数组（包含蛇头）
    @property(Array(Node))
    public bodyArray: Node[] = [];

    //初始时蛇身的数量
    @property(CCInteger)
    public bodyNum: number = 2;

    //蛇身之间的距离
    @property(CCFloat)
    public bodyDistance:number = 50;

    //移动速度的初始值
    speed:number = 200;

    //蛇头的方向
    @property(Vec3)
    snakeDir:Vec3;

    //获取虚拟摇杆
    @property(Node)
    public joystick:Node = null;

    //保存上一帧蛇头的移动方向
    previousMoveDir:Vec3;

    //吃了多少个食物
    @property(Number)
    Score:number = 0;

    //
    @property(AudioClip)
    public eatSound:AudioClip=null;

    //
    @property(AudioClip)
    public DieSound:AudioClip=null; 
 
    //
    @property(RichText)
    public txt_Score:RichText=null;

    //
    @property(Node)
    public startPanel:Node=null;

    //
    @property(Node)
    public gameOverPanel:Node=null;





    protected onLoad(): void {
        //保存蛇头一开始的方向
        this.previousMoveDir = this.node.position.clone().normalize();
        
        //将蛇头添加到蛇身的数组中
        this.bodyArray.push(this.node);

        //设置蛇头的方向
        this.rotateHead(this.node.position);

        //调用产生蛇身的方法
        for(let i=1;i<=this.bodyNum;i++){

            this.getNewBody();
        }

        //设置蛇头出现的位置
        this.node.setPosition(this.randomPos());
            
    }


    start() {

        if(!director.isPaused()){
            director.pause();
        }
        
        //一个用于更新蛇的位置的定时器
        this.schedule(function(){
            this.moveBody()
        },0.2);
        //将食物这个预制体加到场景中
        this.node.parent.addChild(instantiate(this.foodPrefab))
        
        //碰撞的信息检测
        let collider = this.node.getComponent(Collider2D);
        collider.on(Contact2DType.BEGIN_CONTACT,this.onBeginContact,this);

    }

    update(deltaTime: number) {
       

        //将蛇身的移动方向与虚拟摇杆的方向一致
        this.snakeDir = this.joystick.getComponent(Joystick).dir.normalize();

        //判断如果虚拟摇杆的向量为0，就用上一帧的方向付给蛇的方向，使蛇能保持上一帧的方向持续移动
        if(this.snakeDir.length()==0){
            this.snakeDir =this.previousMoveDir.clone().normalize();
        }
        else{
             //将蛇头方向与虚拟摇杆的方向一致
            this.node.angle = this.joystick.getComponent(Joystick).calculateAngle()-90;

            //
            this.previousMoveDir = this.snakeDir;
        }
        //将蛇移动
        let newPos = this.node.position.clone().add(this.snakeDir.clone().multiplyScalar(this.speed*deltaTime));
        this.node.setPosition(newPos);

    }

    getNewBody(){

        //将蛇身预制体实例化
        let newBody = instantiate(this.bodyPrefab);
       
        //如果蛇身数组的长度为1时，只有一个蛇头，则要初始化一个蛇身
        if(this.bodyArray.length < 3){

            //记录蛇头所面向的方向  normalize()可以计算得到模方向上长度为1的点
            let dir =this.node.position.clone().normalize();
            
            //设置蛇身的位置
            newBody.setPosition(this.node.position.clone().subtract(dir.multiplyScalar(this.bodyDistance)));
        }
        else{
            //获取倒数第一个蛇身
            let lastBody = this.bodyArray[this.bodyArray.length-1];
            //获取倒数第二个蛇身
            let lastSecondBody = this.bodyArray[this.bodyArray.length-2];

            //用倒数第二个蛇身的位置减去倒数第一个蛇身的位置，得到的值化为1，即使方向。
            let dir = lastSecondBody.position.clone().subtract(lastBody.position).normalize();
            //设置新的蛇身的位置，在倒数第一个蛇身后50个长度的位置
            newBody.setPosition(lastBody.position.clone().subtract(dir.multiplyScalar(this.bodyDistance)));
            newBody.getComponent(CircleCollider2D).group=16;


        }
        //将蛇身添加到场景中
        this.node.parent.addChild(newBody);

        //将蛇身加入到蛇身数组中
        this.bodyArray.push(newBody);
        //
        this.changZIndex();
    }
    //将蛇身跟随蛇头移动
    moveBody(){
        //保存蛇头的位置
        let headPos = this.node.position;
        //遍历改变蛇身的位置
        for(let i=this.bodyArray.length-2;i>=0;i--){
            //从后往前遍历，后一个蛇身等于前一个蛇身的位置
            this.bodyArray[i+1].position = this.bodyArray[i].position;
        }
        this.bodyArray[1].position = headPos;
    }
   
    //设置蛇身的方向
    rotateHead(headPos){
        let angle = new Vec2(1,0).signAngle(headPos)*180/Math.PI;
        this.node.angle = angle-90;

    }
    //随机蛇头的位置
    randomPos(){

        //获取游戏界面的宽、高
        let width = this.node.parent.getComponent(UITransform).contentSize.width-400;
        let height = this.node.parent.getComponent(UITransform).contentSize.height-300;

        //蛇头出现的位置在画布的中心点，即以画布的的中心为原点移动
        let x = Math.round(Math.random()*width)-width/2;
        let y = Math.round(Math.random()*height)-height/2;

        return new Vec3(x,y,0);
    }

    changZIndex(){
        let lastIndex=this.node.parent.children.length-1
        for(let i=0;i<this.bodyArray.length;i++){
            this.bodyArray[i].setSiblingIndex(lastIndex-i);
        }
    }

    startGame(){
        if(director.isPaused){
            director.resume();
        }
        this.startPanel.active=false;
    }

    restartGame(){
        director.resume();
        director.loadScene("Game");
    }

    //当两个物体碰撞时会被调用
    onBeginContact(SelfCollinder : Collider2D,otherCollider : Collider2D){
        if(otherCollider.group == 4){
            //当食物与蛇头碰撞时，会将食物从它的父节点上移除
            otherCollider.node.removeFromParent();
            this.Score++;

             //右上角得分显示
             this.txt_Score.string="<color=#000000>"+this.Score.toString()+"</color>";

            //食物被吃后，需要在生成一个食物
            let newFood = instantiate(this.foodPrefab);
            this.node.parent.addChild(newFood);

            //吃了食物后蛇身会变长一节
            this.getNewBody();
            //产生音效
            this.node.getComponent(AudioSource).playOneShot(this.eatSound);

        }

        if(otherCollider.group==8||otherCollider.group==16){
            this.gameOverPanel.active=true;
            this.gameOverPanel.getChildByName("Txt_Score").getComponent(Label).string="得分:"+this.Score.toString();
            this.node.getComponent(AudioSource).playOneShot(this.DieSound);
            director.pause();
        }
        
    }
}


